﻿/*
 * @author: wizardc
 */

using System;
using System.Linq;
using System.Text;

namespace Dou.IO
{
    /// <summary>
    /// 字节数组
    /// </summary>
    public class ByteArray
    {
        private byte[] _buffer;
        private Endian _endian;
        private int _position;

        public ByteArray() : this(new byte[0])
        {
        }

        public ByteArray(int size) : this(new byte[size])
        {
        }

        public ByteArray(byte[] buffer)
        {
            _buffer = buffer;
            _endian = Endian.BigEndian;
        }

        public byte[] bytes
        {
            set { _buffer = value; }
            get { return _buffer; }
        }

        public Endian endian
        {
            set { _endian = value; }
            get { return _endian; }
        }

        public int position
        {
            set { _position = value; }
            get { return _position; }
        }

        public int length
        {
            get { return _buffer.Length; }
        }

        public int bytesAvailable
        {
            get
            {
                int available = _buffer.Length - _position;
                if (available > _buffer.Length || available < 0)
                {
                    available = 0;
                }
                return available;
            }
        }

        protected byte[] EndianReverse(byte[] bytes)
        {
            if (BitConverter.IsLittleEndian ^ _endian == Endian.LittleEndian)
            {
                return bytes.Reverse().ToArray();
            }
            return bytes;
        }

        /// <summary>
        /// 读取一个布尔值
        /// </summary>
        public bool ReadBoolean()
        {
            return _buffer[_position++] == 1;
        }

        /// <summary>
        /// 读取一个字节
        /// </summary>
        public sbyte ReadByte()
        {
            return unchecked((sbyte)_buffer[_position++]);
        }

        /// <summary>
        /// 读取一个无符号字节
        /// </summary>
        public byte ReadUnsignedByte()
        {
            return _buffer[_position++];
        }

        /// <summary>
        /// 读取指定的多个字节填满目标字节数组
        /// </summary>
        /// <param name="bytes">读取数据的目标字节数组</param>
        public byte[] ReadBytes(byte[] bytes)
        {
            return ReadBytes(bytes, 0, bytes.Length);
        }

        /// <summary>
        /// 读取指定长度的多个字节
        /// </summary>
        /// <param name="length">读取的长度</param>
        public byte[] ReadBytes(int length)
        {
            return ReadBytes(new byte[length], 0, length);
        }

        /// <summary>
        /// 读取指定的多个字节
        /// </summary>
        /// <param name="bytes">读取数据的目标字节数组</param>
        /// <param name="offset">目标字节数组的起始偏移量</param>
        /// <param name="offset">读取的长度</param>
        public byte[] ReadBytes(byte[] bytes, int offset, int length)
        {
            Buffer.BlockCopy(_buffer, _position, bytes, offset, length);
            _position += length;
            return bytes;
        }

        /// <summary>
        /// 读取一个短整型
        /// </summary>
        public short ReadShort()
        {
            byte[] value = EndianReverse(ReadBytes(2));
            return BitConverter.ToInt16(value, 0);
        }

        /// <summary>
        /// 读取一个无符号短整型
        /// </summary>
        public ushort ReadUnsignedShort()
        {
            byte[] value = EndianReverse(ReadBytes(2));
            return BitConverter.ToUInt16(value, 0);
        }

        /// <summary>
        /// 读取一个 32 位整型
        /// </summary>
        public int ReadInt()
        {
            byte[] value = EndianReverse(ReadBytes(4));
            return BitConverter.ToInt32(value, 0);
        }

        /// <summary>
        /// 读取一个无符号 32 位整型
        /// </summary>
        public uint ReadUnsignedInt()
        {
            byte[] value = EndianReverse(ReadBytes(4));
            return BitConverter.ToUInt32(value, 0);
        }

        /// <summary>
        /// 读取一个 64 位整型
        /// </summary>
        public long ReadLong()
        {
            byte[] value = EndianReverse(ReadBytes(8));
            return BitConverter.ToInt64(value, 0);
        }

        /// <summary>
        /// 读取一个无符号 64 位整型
        /// </summary>
        public ulong ReadUnsignedLong()
        {
            byte[] value = EndianReverse(ReadBytes(8));
            return BitConverter.ToUInt64(value, 0);
        }

        /// <summary>
        /// 读取一个单精度浮点数
        /// </summary>
        public float ReadFloat()
        {
            byte[] value = EndianReverse(ReadBytes(4));
            return BitConverter.ToSingle(value, 0);
        }

        /// <summary>
        /// 读取一个双精度浮点数
        /// </summary>
        public double ReadDouble()
        {
            byte[] value = EndianReverse(ReadBytes(8));
            return BitConverter.ToDouble(value, 0);
        }

        /// <summary>
        /// 读取 UTF-8 字符串，头部使一个 ushort 类型的字符串长度
        /// </summary>
        public string ReadUTF()
        {
            return ReadUTFBytes(ReadUnsignedShort());
        }

        /// <summary>
        /// 读取指定长度的 UTF-8 字符串
        /// </summary>
        /// <param name="length">要读取的长度</param>
        public string ReadUTFBytes(int length)
        {
            string str = Encoding.UTF8.GetString(_buffer, _position, length);
            _position += length;
            return str;
        }

        /// <summary>
        /// 读取指定长度和指定编码格式的字符串
        /// </summary>
        /// <param name="length">要读取的长度</param>
        /// <param name="charSet">编码格式</param>
        public string ReadMultiBytes(int length, string charSet)
        {
            string str = Encoding.GetEncoding(charSet).GetString(_buffer, _position, length);
            _position += length;
            return str;
        }

        /// <summary>
        /// 写入布尔值
        /// </summary>
        public void WriteBoolean(bool value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(new byte[] { bytes[0] });
        }

        /// <summary>
        /// 写入带符号字节
        /// </summary>
        public void WriteByte(sbyte value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(new byte[] { bytes[0] });
        }

        /// <summary>
        /// 写入无符号字节
        /// </summary>
        public void WriteUnsignedByte(byte value)
        {
            WriteBytes(new byte[] { value });
        }

        /// <summary>
        /// 写入指定的字节数组
        /// </summary>
        /// <param name="value">字节数组</param>
        public void WriteBytes(byte[] value)
        {
            WriteBytes(value, 0, value.Length);
        }

        /// <summary>
        /// 写入指定的字节数组
        /// </summary>
        /// <param name="byteArray">字节数组</param>
        public void WriteBytes(ByteArray byteArray)
        {
            byte[] buffer = byteArray.ReadBytes(byteArray.bytesAvailable);
            WriteBytes(buffer);
        }

        /// <summary>
        /// 写入指定的字节数组
        /// </summary>
        /// <param name="bytes">字节数组</param>
        /// <param name="offset">写入字节数组的偏移量</param>
        /// <param name="length">写入的长度</param>
        public void WriteBytes(byte[] value, int offset, int length)
        {
            int next = length + _position;
            int size = next;
            if (size <= _buffer.Length)
            {
                size = _buffer.Length;
            }
            byte[] destination = new byte[size];
            Buffer.BlockCopy(_buffer, 0, destination, 0, _buffer.Length);
            Buffer.BlockCopy(value, offset, destination, _position, length);
            _position = next;
            _buffer = destination;
        }

        /// <summary>
        /// 写入带符号短整型
        /// </summary>
        public void WriteShort(short value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(EndianReverse(bytes));
        }

        /// <summary>
        /// 写入无符号短整型
        /// </summary>
        public void WriteUnsignedShort(ushort value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(EndianReverse(bytes));
        }

        /// <summary>
        /// 写入带符号整型
        /// </summary>
        public void WriteInt(int value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(EndianReverse(bytes));
        }

        /// <summary>
        /// 写入无符号整型
        /// </summary>
        public void WriteUnsignedInt(uint value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(EndianReverse(bytes));
        }

        /// <summary>
        /// 写入带符号长整型
        /// </summary>
        public void WriteLong(long value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(EndianReverse(bytes));
        }

        /// <summary>
        /// 写入无符号长整型
        /// </summary>
        public void WriteUnsignedLong(ulong value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(EndianReverse(bytes));
        }

        /// <summary>
        /// 写入单精度浮点数
        /// </summary>
        public void WriteFloat(float value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(EndianReverse(bytes));
        }

        /// <summary>
        /// 写入双精度浮点数
        /// </summary>
        public void WriteDouble(double value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            WriteBytes(EndianReverse(bytes));
        }

        /// <summary>
        /// 写入 UTF-8 字符串，头部带上一个 ushort 类型的字符串长度
        /// </summary>
        public void WriteUTF(string value)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(value);
            int length = bytes.Length;
            if (length > short.MaxValue)
            {
                throw new FormatException("文本长度超过上限");
            }
            WriteUnsignedShort((ushort)length);
            WriteBytes(bytes);
        }

        /// <summary>
        /// 写入 UTF-8 字符串
        /// </summary>
        public void WriteUTFBytes(string value)
        {
            WriteBytes(Encoding.UTF8.GetBytes(value));
        }

        /// <summary>
        /// 写入指定编码格式的字符串
        /// </summary>
        /// <param name="charSet">编码格式</param>
        public void WriteMultiBytes(string value, string charSet)
        {
            WriteBytes(Encoding.GetEncoding(charSet).GetBytes(value));
        }

        public void Clear()
        {
            _buffer = new byte[0];
            _endian = Endian.BigEndian;
            _position = 0;
        }
    }
}
